#include "KickBehaviour.h"
#include "TurnToBehaviour.h"


/*
 *	Kopne na dane miesto
 *
 *	@param target	pozicia, kam sa ma kopnut
 */
void KickBehaviour::Behave(const Point& target)
{
	static float reqPower, dirDiff, distBall;
	reqPower = world->params->server->maxpower * world->params->server->kick_power_rate;
	dirDiff = ((world->ball->pos - world->me->pos) - world->me->GetAbsDir()).GetAngle().GetAbsDeg();
	distBall = (world->ball->pos - world->me->pos).GetLength() - world->params->server->ball_size - world->params->server->player_size;
	reqPower *= 1.f - 0.25f * dirDiff / 180.f - 0.25f * distBall / world->me->type->kickable_margin;

	TXTN("NEW KICK: power=%.2f",reqPower);

	Point T1;
	if(GetLineCircleIntersect(world->ball->pos, target, world->ball->pos+world->ball->vel, reqPower, T1) == 0)
	{
		TXTN("KICK1: (%.2f, %.2f) => (%.2f, %.2f)", world->ball->pos.GetX(), world->ball->pos.GetY(), target.GetX(), target.GetY());
		commandGenerator->Kick(world->params->server->maxpower, CalcDir(target - world->ball->pos, world->me->GetAbsDir()).GetDeg());
		GetTurnToBehaviour()->Behave(target);
	}
	else
	{
		TXTN("KICK2: (%.2f, %.2f) => newpos (%.2f, %.2f)", world->ball->vel.GetX(), world->ball->vel.GetY(), 
			T1.GetX(), T1.GetY());
		commandGenerator->Kick(world->params->server->maxpower, CalcDir((T1 - (world->ball->pos+world->ball->vel)), world->me->GetAbsDir()).GetDeg());
		GetTurnToBehaviour()->Behave(T1);
	}
}

/*
 * Kopnutim sa natoci lopta
 */
void KickBehaviour::TurnBall()
{
	SKILLS_DBGN("%i: ->turn ball", world->state->GetSimTime());

	// Ak je dostatocne blizko
	if(DATA_STORAGE.IsBallKickable())
	{
		Angle targetAngle = DATA_STORAGE.ballDiff.GetAngle() + DegAngle(0.4f * 180.f);
		const float controlDistance = world->me->type->player_size + 
			world->params->server->ball_size + 0.45f * world->me->type->kickable_margin;
		Vector relativeTarget = PolarVector(controlDistance, targetAngle);

		// Miesto pozadovaneho kopnutia
		Point ciel = (world->me->pos + world->me->vel + relativeTarget);
		GetNearKickBehaviour()->Behave(ciel);
	}
	else // Nemozeme kopnut
	{
		return;
	}
}

/*
 * Zisti silu potrebnu na kopnutie lopty na urcite miesto za urcity pocet cyklov
 * @param ciel miesto, kde sa ma lopta kopnut
 * @param steps kolko cyklov to ma trvat
 *
 * @return vrati sa pozadovana sila kopnutia
 */
float KickBehaviour::GetKickPower(const Point& target, int steps)
{
	int stepTolerance = 5;
	Vector path = target - world->ball->pos;
	float distance = path.GetLength();
	float requiredSpeed = distance * (1.0f - world->params->server->ball_decay) / (1.0f - float(pow(world->params->server->ball_decay, steps - 1)));
  
	if (requiredSpeed > world->params->server->ball_speed_max)
	{
		requiredSpeed = distance * (1.0f - world->params->server->ball_decay) / (1.0f - float(pow(world->params->server->ball_decay, steps + stepTolerance)));
		return requiredSpeed;
    }
  
	return requiredSpeed;
}

/*
 * Prihra na dane miesto kratkym kopnutim, ak sa tam dostane skor ako superi
 *
 * @param pos miesto kam chceme prihravat
 *
 * @return ak sa vykonala prihravka true, ak nie false
 */
bool KickBehaviour::ShortKick(const Point& position)
{
	SKILLS_DBGN("%i: ->short kicking to position", world->state->GetSimTime());
	SKILLS_DBGN("%i: ->pos (%3.2f, %3.2f)", world->state->GetSimTime(), position.GetX(), position.GetY());

	const Vector diff = position - world->ball->pos;
	const float distance = diff.GetLength();
	
	if(distance == 0)
		return false;

	if(!world->me->IsLookingAt(position))
		return false;

	for(float d = 15.0f;d >= 5.0f; d -= 1.0f)
	{
		const Point target = world->ball->pos + diff * (d/distance);
		const int mySteps = GetRunToPositionBehaviour()->PredictSteps((target - world->me->pos).GetLength(),
			GetRunToPositionBehaviour()->RecommDashPower(true),0);
		float enemySteps = 6000; // velke cislo

		for(int i = 0; i < world->enemies.GetSize(); i++)
		{
			enemySteps = min(enemySteps, (target - world->enemies[i].pos).GetLength()/world->params->server->player_speed_max);
		}

		if(mySteps < enemySteps)
		{
			GetPassBallToBehaviour()->Behave(target,0);
			return true;
		}
	}

	return false;
}
